/**
 * 
 */
package recognition.engine.metric;

import handwritten.character.CharacterCollection;
import handwritten.character.CharacterCollectionManager;
import handwritten.character.HandWritten;
import handwritten.character.HandWrittenCharacter;
import handwritten.character.ModifiedHWCharacter;
import handwritten.character.RawHandWrittenCharacter;
import handwritten.gesture.Gesture;
import handwritten.gesture.MultiGesture;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Set;

import auth.User;
import recognition.engine.RecognitionEngine;
import recognition.engine.Recognizer;
import recognition.input.Input;
import recognition.input.MGestureInput;
import recognition.output.PredictedCharacter;
import recognition.preprocessor.LengthSetter;
import recognition.preprocessor.Preprocessor;
import recognition.preprocessor.RemoveTwoFollowingSamePoint;
import recognition.preprocessor.Resampling;
import recognition.preprocessor.Smoother;

/**
 * @author tioz
 *
 */
public class BasicMetric extends Recognizer {

	/**
	 * 
	 */
	
	private RecognitionEngine engine;
	private CharacterCollection<ModifiedHWCharacter> target;
	
		
	public BasicMetric(RecognitionEngine engine,double strength) {
		super(strength);
		this.engine=engine;
		getPreprocessedCollection();
	}

	/* (non-Javadoc)
	 * @see recognition.engine.Recognizer#process(java.util.Hashtable)
	 */
	@Override
	public ArrayList<PredictedCharacter> process(
		
		Hashtable<Class<? extends Input<?>>, Input<?>> inputs) {
		
		ArrayList<PredictedCharacter> results = new ArrayList<PredictedCharacter>();
		Hashtable<Class<? extends Input<?>>,Input<?>> nInputs = new Hashtable<Class<? extends Input<?>>, Input<?>>();
		
		MultiGesture gest = (MultiGesture) inputs.get(MGestureInput.class).getInput();
		
		
		double error  ;
		double cumErr=0 ;
		
		for(String k : target.getCollection().keySet())
		{
			//for(ModifiedHWCharacter t: target.getCollection().get(k))
			ModifiedHWCharacter t = target.getCollection().get(k).get(0);
			System.out.println("using "+k);
				error  = 0;
				
					error  = difference(gest, t.getGesture());

					if(!Double.isNaN(error))
					{
						cumErr += error;
						results.add(new PredictedCharacter(k, error));
					}
		}
		
		for(PredictedCharacter p : results)
		{
			p.normalise(cumErr);
		}
		System.out.println("finish");
		return results;
	}
		
	
	
	
	
	protected double difference(MultiGesture gest1, MultiGesture gest2)
	{
		ArrayList<Double> err = new ArrayList<Double>() ;
		
		if( gest1.numberOfGesture()== gest2.numberOfGesture())
		{
			
			for(int i=0; i < gest1.numberOfGesture(); i++)
			{
				err.addAll(difference(gest1.get(i), gest2.get(i)));
			}
			if(Double.isNaN(err.get(err.size()-1)))
			{
				return Double.NaN ;
			}
		}
		
		double mean=0;
		double sigma=0;
		
		for(double d : err)
		{
			mean +=d;
		}
		
		mean = mean/err.size();
		
		for(double d : err)
		{
			sigma = (mean - d)*(mean - d);
		}
		
		return sigma;
	}
	
	
	
	
	
	protected ArrayList<Double> difference(Gesture gest1 , Gesture gest2){
		ArrayList<Double> err = new ArrayList<Double>();
		
		int diffL= gest2.size()-gest1.size();
		
		System.out.println("diffL " + diffL);
		//gest 1 is the biggest
		if(diffL >0)
		{
			 Gesture tmp = gest2;
			 gest2 = gest1;
			 gest1=tmp;
		}
		
		double min = Double.MAX_VALUE;
		double tmp;
		int iMin=0;
		
		
		if(Math.abs(diffL) < gest2.size())
		{
			
			//find a the "best starting point" 
			for(int i=0; i< Math.abs(diffL); i++)
			{
				tmp = gest1.get(i).minus(gest2.get(i)).normSquared();
				if(min > tmp)
				{
					min = tmp;
					iMin = i;
				}
			}
						
			for(int i=iMin ; i < gest1.size(); i++)
			{
				err.add(gest1.get(i).minus(gest2.get(2)).normSquared());
			}
			
			
			return err;
		}
		else
		{
			err.add(Double.NaN);
			return err;
		}
	}
	
	
	
		
	
	
	//return an uniformely processed collection
	@SuppressWarnings("unchecked")
	protected CharacterCollection<ModifiedHWCharacter> getPreprocessedCollection()
	{
		//take first user
		//FIXME
		User u = CharacterCollectionManager.getInstance().getUsers().iterator().next();
		
		//initialise collectoin and input
		target = (CharacterCollection<ModifiedHWCharacter>)CharacterCollectionManager.getInstance().getCollection(u,"BasiMetric",ModifiedHWCharacter.class);
		target.clear();
		Hashtable<Class<? extends Input<?>>,Input<?>> inputs = new Hashtable<Class<? extends Input<?>>, Input<?>>();
		
		//load collection
		CharacterCollection<RawHandWrittenCharacter> characters = (CharacterCollection<RawHandWrittenCharacter>)CharacterCollectionManager.getInstance()
				.getCollection(u,"default",RawHandWrittenCharacter.class );
		
		//initialise needed variable
		HandWrittenCharacter c;
		ModifiedHWCharacter processed;
		
		Hashtable<String, ArrayList<RawHandWrittenCharacter>> coll = characters.getCollection();
		for(String k : coll.keySet())
		{	
			for(RawHandWrittenCharacter raw : coll.get(k) )
			{
			   c=raw.getHandwritten();
			   System.out.println("id is : " + c.getId()  );
	   
			   engine.getPpRoot().preprocess(c.getGesture(),inputs);
			  
			   processed = new ModifiedHWCharacter(c.getId(),(MultiGesture)inputs.get(MGestureInput.class).getInput(),inputs);
			   target.addSample(processed);
			}
		}
		for(User user1 : CharacterCollectionManager.getInstance().getUsers()){
			ArrayList<CharacterCollection<?>> cols = CharacterCollectionManager.getInstance().getCollections(user1);
			for(CharacterCollection<?> col : cols){
				if(col.getType().equals(ModifiedHWCharacter.class))
				{
					for(String k : col.getCollection().keySet() )
					{
						((ModifiedHWCharacter)col.get(k, 0)).getGesture().paintInNewFrame(((ModifiedHWCharacter)col.get(k, 0)).getId());
					}
				}
					
			}
		}
		
		return target;
	}
	

}
